package com.pxmeta.party.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.pxmeta.common.constant.HttpStatus;
import com.pxmeta.common.constant.Status;
import com.pxmeta.common.core.domain.AjaxResult;
import com.pxmeta.common.exception.ServiceException;
import com.pxmeta.common.utils.agora.AgoraClient;
import com.pxmeta.party.entity.Association;
import com.pxmeta.party.entity.AssociationUser;
import com.pxmeta.party.entity.Party;
import com.pxmeta.party.entity.PartyUser;
import com.pxmeta.party.entity.dto.DispatchDTO;
import com.pxmeta.party.entity.dto.OperateDispatchDTO;
import com.pxmeta.party.entity.dto.SetPasswordDTO;
import com.pxmeta.party.entity.enums.PartyUserRoleEnum;
import com.pxmeta.party.entity.dto.CreatePartyDTO;
import com.pxmeta.party.entity.vo.ChannelResultVO;
import com.pxmeta.party.entity.vo.ChannelUserVO;
import com.pxmeta.party.entity.vo.ChannelsVO;
import com.pxmeta.party.mapper.PartyMapper;
import com.pxmeta.party.service.*;
import com.pxmeta.user.entity.User;
import com.pxmeta.user.entity.vo.AnchorVO;
import com.pxmeta.user.entity.vo.UserVO;
import com.pxmeta.user.service.IUserBillService;
import com.pxmeta.user.service.IUserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 语聊派对表 服务实现类
 * </p>
 *
 * @author wcl
 * @since 2022-06-25
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class PartyServiceImpl extends ServiceImpl<PartyMapper, Party> implements IPartyService {

    @Autowired
    private  IPartyUserService partyUserService;

    @Autowired
    private IUserBillService userBillService;

    @Autowired
    private  IAssociationService associationService;

    @Autowired
    private IAssociationUserService associationUserService;

    @Autowired
    private  IUserService userService;

    @Autowired
    private AgoraClient agoraClient;

    @Override
    public String getPartyNumber() {
        Integer count = baseMapper.getCount();
        count += 100000;
        return "" +count;
    }

    @Override
    @Transactional
    public Party createParty(CreatePartyDTO dto, Long userId) {

        Integer type = dto.getType();
        User user = userService.getById(userId);
        Integer isAuthIdentity = user.getIsAuthIdentity();
        Long associationId = user.getAssociationId();
//        if (type != 4 && !Status.SUCCESS.getValue().equals(isAuthIdentity)){
//            throw new ServiceException("请完成实名认证！", HttpStatus.USER_NO_AUTH_IDENTITY);
//        }

        Party lastPersonalLive = this.getLastPersonalLive(userId,type);
        if (null != lastPersonalLive){
            return lastPersonalLive;
        }

        Party party = new Party();

        String number = this.getPartyNumber();
        party.setId(dto.getPartyId());
        party.setNotice(dto.getNotice());
        party.setCircleId(1L);
        party.setUserId(userId);
        party.setTitle(dto.getTitle());

        if (StringUtils.isBlank(dto.getImgUrl())){
            party.setImgUrl(user.getAvatar());
        }else {
            party.setImgUrl(dto.getImgUrl());
        }
        party.setType(type);
        party.setNumber(number);
        party.setAssociationId(associationId);
        this.save(party);


        //如果是公会房间，则只能创建一次，且派对与公会绑定。
        if (type == 3 || type == 6 || type == 7 || type == 8){

            if (associationId == null){
                this.joinParty(party.getId(),userId, PartyUserRoleEnum.OWNER.getRole());
                return party;
            }

            Association association = associationService.getById(associationId);
            String partyId = association.getPartyIds();

            String id = party.getId();
            if (StringUtils.isNotBlank(partyId)){
                List<String> partyIds = new ArrayList<>(Arrays.asList(partyId.split(",")));
                partyIds.add(id);
                String finalPartyIds = StrUtil.join(",", partyIds);
                association.setPartyIds(finalPartyIds);
            }else {
                association.setPartyIds(id);
            }
            party.setAssociationId(associationId);
            this.updateById(party);


            if (type == 3){
                if (StringUtils.isNotBlank(association.getPartyId())){
                    throw new ServiceException("无法重复创建公会房间！");
                }else {
                    association.setPartyId(dto.getPartyId());
                }
            }
            associationService.updateById(association);


        }




        this.joinParty(party.getId(),userId, PartyUserRoleEnum.OWNER.getRole());
        return party;
    }

    @Override
    @Transactional
    public PartyUser joinParty(String partyId, Long userId, Integer role) {
        Party party = this.getById(partyId);

        Boolean isHidden = party.getIsHidden();
        if (isHidden){
            party.setIsHidden(Boolean.FALSE);
        }
        Integer onlineCount = party.getOnlineCount();
        Integer hot = party.getHot();
        hot += 10;
        onlineCount ++;
        party.setOnlineCount(onlineCount);
        party.setHot(hot);
        this.updateById(party);
//        LambdaQueryWrapper<PartyUser> wrapper = Wrappers.lambdaQuery();
        PartyUser partyUser = baseMapper.getOne(userId, partyId);
        log.info("partyUser...{}",partyUser);
        if (null == partyUser){
            partyUser = new PartyUser();
            partyUser.setPartyId(partyId);
            partyUser.setUserId(userId);
            partyUser.setRole(role);
            partyUserService.save(partyUser);
        }
        return partyUser;
//        //清除其他派对房数据
//        wrapper.clear();
//        wrapper.eq(PartyUser::getUserId, userId)
//                .ne(PartyUser::getPartyId, partyId);
//        List<PartyUser> rmList = partyUserService.list(wrapper);
//
//        if (CollectionUtils.isNotEmpty(rmList)){
//            partyUserService.removeBatchByIds(rmList);
//        }
    }

    @Override
    @Transactional
    public void dissolution(Long userId, Long partyId) {
        Party party = this.getById(partyId);
        if (!userId.equals(party.getUserId())){
            throw new ServiceException("没有权限解散！", HttpStatus.PARAMS_ERROR);
        }
        if (party.getType() == 5){
            party.setIsHidden(Boolean.TRUE);
            this.updateById(party);
            return;
        }
        LambdaQueryWrapper<PartyUser> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(PartyUser::getPartyId, partyId);
        List<PartyUser> list = partyUserService.list(wrapper);

        if (CollectionUtils.isNotEmpty(list)){
            partyUserService.removeBatchByIds(list.stream().map(PartyUser::getId).collect(Collectors.toList()));
        }

        this.removeById(party);
    }

    @Override
    @Transactional
    public void signOut(Long userId, Long partyId) {
        LambdaQueryWrapper<PartyUser> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(PartyUser::getUserId, userId)
                .eq(PartyUser::getPartyId, partyId);
        PartyUser partyUser = partyUserService.getOne(wrapper);
        if (null == partyUser){
            throw new ServiceException("你已经不在该派对！",HttpStatus.PARAMS_ERROR);
        }
        Party party = this.getById(partyId);
        Integer onlineCount = party.getOnlineCount();
        onlineCount --;
        party.setOnlineCount(onlineCount);
        this.updateById(party);
//        partyUserService.removeById(partyUser);
    }

    @Override
    public List<AnchorVO> getAnchorList() {
        ChannelResultVO channelResult = agoraClient.getChannelList(1, 10).toJavaObject(ChannelResultVO.class);
        List<ChannelsVO> channels = channelResult.getChannels();
        List<String> channelIds = channels.stream().map(ChannelsVO::getChannelName).collect(Collectors.toList());
        LambdaQueryWrapper<Party> wrapper = Wrappers.lambdaQuery();

        if (CollectionUtil.isEmpty(channelIds)){
            return Lists.newArrayList();
        }
        wrapper.ne(Party::getType,4);
        wrapper.in(Party::getId,channelIds);
        wrapper.orderByDesc(Party::getOnlineCount);
        List<Party> partyList = this.page(new Page<>(1, 10),wrapper).getRecords();
        if (partyList.isEmpty()){
            return Lists.newArrayList();
        }


        List<AnchorVO> anchorList = Lists.newLinkedList();
        for (Party party : partyList) {
            if (anchorList.size()>=10){
                break;
            }
            ChannelUserVO userVO = agoraClient.getUsers(party.getId()).toJavaObject(ChannelUserVO.class);
            List<Integer> usernames = userVO.getBroadcasters();
            List<UserVO> users = userService.getUserVOListByUsername(usernames);
            for (UserVO user : users) {
                AnchorVO anchorVO = new AnchorVO();
                BeanUtils.copyProperties(user, anchorVO);
                anchorVO.setPartyId(party.getId());
                anchorVO.setPartyTitle(party.getTitle());
                anchorList.add(anchorVO);
            }
        }
        return anchorList;
    }

    @Override
    @Transactional(rollbackFor = ServiceException.class)
    public void addAdmin(String partyId, String adminUsername,Integer type) {
        User adminUser = userService.getByUsername(adminUsername);
        PartyUser partyUser = partyUserService.getPartyUser(partyId, adminUsername);

        Integer role = PartyUserRoleEnum.ADMIN.getRole(); //默认是管理员
        if (type != null && type == 1){
            //超级管理员
            //查看放假超级管理员数量
            PartyUser superAdmin = this.getSuperAdmin(partyId);
            if (null != superAdmin){
                throw new ServiceException("超级管理员只能添加一个！");
            }

            role = PartyUserRoleEnum.SUPER_ADMIN.getRole();
        }
        log.info("添加管理员========》username:{}, partyId:{}, partyUser: {}", adminUsername, partyId, partyUser);
        if (null == partyUser){
            PartyUser joinPartyUser = this.joinParty(partyId, adminUser.getId(), role);
            joinPartyUser.setRole(role);
            partyUserService.updateById(joinPartyUser);
        }else {
            partyUser.setRole(role);
            partyUserService.updateById(partyUser);
        }

    }

    private PartyUser getSuperAdmin(String partyId) {
        LambdaQueryWrapper<PartyUser> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(PartyUser::getPartyId, partyId)
                .eq(PartyUser::getRole, PartyUserRoleEnum.SUPER_ADMIN.getRole());

        return partyUserService.getOne(wrapper);
    }

    @Override
    public List<User> getAdminList(String partyId) {
        return partyUserService.getAdminUsers(partyId);
    }

    @Override
    public void removeAdmin(String partyId, String adminUsername) {
        PartyUser partyUser = partyUserService.getPartyUser(partyId, adminUsername);
        if (null == partyUser){
            throw new ServiceException("该用户已不在房间！");
        }
        partyUser.setRole(PartyUserRoleEnum.NORMAL.getRole());
        partyUserService.updateById(partyUser);
    }

    @Override
    public String getRandomPartyId(Integer type) {
        LambdaQueryWrapper<Party> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(Party::getType,type)
                .orderByDesc(Party::getHot,Party::getCreateTime)
                .last("limit 100");
        List<Party> list = this.list(wrapper);

        if (list.isEmpty()){
            return null;
        }
        Collections.shuffle(list);
        return list.get(0).getId();
    }

    @Override
    public List<User> getSuperAdminList(String partyId) {
        LambdaQueryWrapper<PartyUser> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(PartyUser::getPartyId, partyId)
                .eq(PartyUser::getRole, PartyUserRoleEnum.SUPER_ADMIN.getRole());

        List<PartyUser> list = partyUserService.list(wrapper);
        List<Long> userIds = list.stream().map(PartyUser::getUserId).collect(Collectors.toList());
        if (userIds.isEmpty()){
            return Lists.newLinkedList();
        }
        return userService.listByIds(userIds);
    }

    @Override
    public Integer getAssociationRole(Long userId) {

        User user = userService.getById(userId);
        Long associationId = user.getAssociationId();
        if (associationId==null){
            return PartyUserRoleEnum.NORMAL.getRole();
        }
        Association association = associationService.getById(associationId);
        if (association.getPresidentUserId().equals(userId)){
            return PartyUserRoleEnum.OWNER.getRole();
        }
        AssociationUser associationUser = associationUserService.getUserSign(userId);
        if (associationUser != null && associationUser.getIsAdmin()){
            return PartyUserRoleEnum.SUPER_ADMIN.getRole();
        }
        return PartyUserRoleEnum.NORMAL.getRole();
    }

    @Override
    public IPage<Party> getAssociationPartyList(Integer page, Integer size, Long associationId, String keyword) {
        LambdaQueryWrapper<Party> wrapper = Wrappers.lambdaQuery();
        if (associationId == null) {

        }else {
            wrapper.eq(Party::getAssociationId, associationId);
        }

        if (StringUtils.isNotBlank(keyword)){
            wrapper.eq(Party::getNumber, keyword);
        }
        wrapper.orderByAsc(Party::getIsHidden)
                .orderByDesc(Party::getHot);
        Page<Party> result = this.page(new Page<>(page, size), wrapper);
        for (Party record : result.getRecords()) {
            Double totalBillNumber = userBillService.getTotalBillNumber(record.getId(), null);
            Double weekNumber = userBillService.getTotalBillNumber(record.getId(), 1);
            Double todayNumber = userBillService.getTotalBillNumber(record.getId(), 2);
            Double yesterdayNumber = userBillService.getTotalBillNumber(record.getId(), 3);

            record.setYesterdayBillNumber(yesterdayNumber);
            record.setTotalBillNumber(totalBillNumber);
            record.setWeekBillNumber(weekNumber);
            record.setTodayBillNumber(todayNumber);
        }
//        List<Party> records = result.getRecords();
        return result;

//        for (Party record : records) {
//            Long getTotalBill = userBillService.getTotalBill(record.getId());
//            //
//        }
//
//        return ;

    }

    @Override
    public void setPassword(SetPasswordDTO dto) {
        Party party = this.getById(dto.getPartyId());
        party.setPassword(dto.getPassword());
        this.updateById(party);
    }

    @Override
    public Boolean checkPassword(String partyId, String password) {
        Party party = this.getById(partyId);

        return password.equals(party.getPassword());
    }

    @Override
    public Party getLastPersonalLive(Long userId,Integer type) {
        LambdaQueryWrapper<Party> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(Party::getUserId, userId)
                .eq(Party::getType, type)
                .orderByDesc(Party::getCreateTime);

        List<Party> list = this.list(wrapper);
        if (!list.isEmpty()){
            Party party = list.get(0);
            list = list.stream().filter(p->!p.getId().equals(party.getId())).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(list)){
                this.removeBatchByIds(list);
            }
            return party;
        }

        return null;
    }


}
